﻿using System;
using System.IO;
using System.Threading;

using Coding4Fun.BoxingBots.Robot.Helpers;

using Phidgets;
using Phidgets.Events;

namespace Coding4Fun.BoxingBots.Robot
{
	public class PhidgetController : IDisposable
	{
		private const string PhidgetFileName = "phidget21";
		private const string PhidgetFullFileName = "phidget21.dll";

		private readonly InterfaceKit _phidgetInterfaceKit;
		private readonly LED _phidgetLed;

		readonly AutoResetEvent _waitForInterfaceKitLoad = new AutoResetEvent(false); // prevent race event to be sure phidgets fully loaded and online
		readonly AutoResetEvent _waitForLedLoad = new AutoResetEvent(false); // prevent race event to be sure phidgets fully loaded and online

		private static bool _isInterfaceKitLoaded;
		private static bool _isLedLoaded;

		public PhidgetController()
		{
			CopyOsPhidgetDll();

			_phidgetInterfaceKit = new InterfaceKit();
			_phidgetLed = new LED();

			_phidgetInterfaceKit.Attach += PhidgetInterfaceKitAttach;
			_phidgetLed.Attach += PhidgetLedAttach;

            _phidgetLed.open();
            _phidgetInterfaceKit.open();

			_waitForInterfaceKitLoad.Reset();
			_waitForLedLoad.Reset();
		}

		void PhidgetLedAttach(object sender, AttachEventArgs e)
		{
			_isLedLoaded = true;
			
			_waitForLedLoad.Set();
		}

		void PhidgetInterfaceKitAttach(object sender, AttachEventArgs e)
		{
			_isInterfaceKitLoaded = true;
	
			_waitForInterfaceKitLoad.Set();
		}

		private LedController _leds;
		public LedController Leds
		{
			get
			{
				if (!_phidgetLed.Attached)
					return null;

                if (!_isLedLoaded)
                    _waitForLedLoad.WaitOne();

				return _leds ?? (_leds = new LedController(_phidgetLed));
			}
		}

		private RelayController _relay;
		public RelayController Relays
		{
			get
			{
				if (!_phidgetInterfaceKit.Attached)
					return null;

                if (!_isInterfaceKitLoaded)
					_waitForInterfaceKitLoad.WaitOne();

				return _relay ?? (_relay = new RelayController(_phidgetInterfaceKit));
			}
		}

		private SensorController _sensors;
		public SensorController Sensors
		{
			get
			{
				if (!_phidgetInterfaceKit.Attached)
					return null;

                if (!_isInterfaceKitLoaded)
					_waitForInterfaceKitLoad.WaitOne();

				return _sensors ?? (_sensors = new SensorController(_phidgetInterfaceKit));
			}
		}

		private static void CopyOsPhidgetDll()
		{
			var fileName = string.Format(
					"Dependencies/{0}_{1}.dll",
				//PhidgetFileName, (OsDetect.Is64Bit()) ? "64" : "86"),
				// for some reason 64 driver has issues with the 0/0/4
				// reported issue to phidgets
					PhidgetFileName, "86");

			if (!File.Exists(PhidgetFullFileName) || FileHelper.GetMD5Hash(fileName) != FileHelper.GetMD5Hash(PhidgetFullFileName))
				File.Copy(fileName, PhidgetFullFileName, true);
		}

		public void Dispose()
		{
			_waitForInterfaceKitLoad.Dispose();
			_waitForLedLoad.Dispose();

			_relay.Dispose();
			_sensors.Dispose();
			_leds.Dispose();

			if (_phidgetInterfaceKit != null)
			{
				_phidgetInterfaceKit.Attach -= PhidgetInterfaceKitAttach;
				_phidgetInterfaceKit.close();
			}

			if (_phidgetLed != null)
			{
				_phidgetLed.Attach -= PhidgetInterfaceKitAttach;
				_phidgetLed.close();
			}
		}
	}
}
